//TODO: Handle adding heap data to checkpoints
//TODO: ENUMERATE STATE
//TODO: ENUMERATE ARCH EXTNS
//TODO: REASON ABOUT SEMANTICS *DURING* RECOVERY

int main(argc, argv){


  /*FAILURE_BIT - this is an architecture feature.
  The failure bit is 1-bit of non-volatile state.
  The device sets this bit when it is browning out.
  It is part of the ABI to reset this bit on program
  start. 
  */
  if( GET_FAILURE_BIT() ){


    /*LD_CURR_CP_AFTER_RECOVERY_RTN - this is an architecture feature.  
      It takes a code pointer to a function that does recovery.  This 
      operation records the code pointer arg into a special register
      that isn't overwritten by checkpoints.  Then this operation 
      loads the checkpoint.  Then this operation pushes a new stack frame
      that jumps to the code pointed to by the special register.  When that code,
      returns, the new stack frame is popped and control flows to the
      program counter in the "current" checkpoint. */
    LD_CURR_CP_AFTER_RECOVERY_RTN( 

      /*GET_RECOVERY_ROUTINE - this is an architecture feature.
        It takes two arguments: a integer that indexes a table that stores
        recovery routine IDs and a register to store the address of the
        recovery routine.  This operation loads the recovery routine 
        address from the table into the register.
      */
      GET_RECOVERY_ROUTINE( 

                           /*GET_DEATH_ID() - this is an architecture feature.
                             It returns the value stored in the non-volatile DEATH_ID register
                             the DEATH_ID register gets set by the SET_DEATH_ID
                             operation, at the beginning of a try block.
                           */
                           GET_DEATH_ID() ); 

    );

  }
  
  /*CLEAR_FAILURE_BIT - this is an architecture feature.
  The purpose of this operation is to store a 0 to the 
  1-bit FAILURE_BIT 
  */
  CLEAR_FAILURE_BIT();

  /*STORE_EXPLICIT_CHECKPOINT - this is an architecture feature.
    This operation takes an integer argument that serves
    as the index for retreiving this checkpoint later.
    Checkpoints can be retrieved by calling LOAD_EXPLICIT_CHECKPOINT
  */
  STORE_EXPLICIT_CHECKPOINT(0); 
  
  Object *o = NULL;
  Object *p = NULL;
  Object *q = NULL; 

  initConstants(o,p,q);/*Same values for each run - from config file, say*/
  
  initFirehose(o,p,q);/*results in firehoseState == Firehose.valid*/
  
  bool lastEvent = false;/*flag - ends loop*/

  sendFireHoseInitMessage();
  /*Browning out any time before this, it would just be better to
    start from beginning of main, than to complicate this code.
    After this, though, we've started processing events, so it's better
    to not brown out to start of main*/

  /*See above*/
  STORE_EXPLICIT_CHECKPOINT(1);

  while( !lastEvent ){
      lastEvent = handleEvent();
  } 

}

void handleEvent(){

  /*Default: Stuff is preserved across failures.  Illusion of continuity*/

  /*This is confusing.  We can do better than this.  Here's what it means:
    e is a pointer to an event (Event *).  e is stored on the stack;  *e is an event
    that will be on the heap.  

    The default for stack & reg is that they are preserved.  The default for 
    heap is that it is not preserved.  So we need to tell the system that
    this is a preserved Event pointed to by a plain
    old stack thing that is preserved by default. 

    Deeply unsatisfying.  Programmer: "How do i know what to preserve???  Everything???"
  */

  //Try{/*TODO: EXPLICIT_CHECKPOINT here too??*/

    /*SET_DEATH_ID - this is an architecture feature.  This operation
    takes one argument and sets the non-volatile DEATH_ID register
    to that value.  The compiler separately numbers try blocks and 
    assigns these. */
    SET_DEATH_ID(0); //This is the first Try{}, so it is DEATH_ID 0;

    Event __attribute__((preserved)) *e;

    SensorValue __attribute__((preserved)) *sval; 

    SensorState sstate; 

    e = getEventFromFirehose();/*from an external object fountain*/
    STASH(e,sizeof(Event),0x0) //Static STASH allocation
    

    sval = malloc(...);

    if( e->onTheHour == true ){

      sstate = getSensorState();//preserved on the stack

      if( sstate == SensorState.valid ){

        sval = getOnTheHourSensorReading();//this is a heap var!
        //TODO:what happens in here...  we need atomicity or we lose the value...
        STASH(sval,sizeof(SensorValue),0x0 + sizeof(Event)) //Static STASH allocation

        int d = sval.asInt() / 12;

        if( d == MAX ){

          return true;

        }else{

          return false;

        }

      }else{

        return false;

      }

    }else{

      return false;

    }
  /*}Recover{ } has been moved into the Recover_0 function*/

}


void Recover_0(){

    //}Recover{
      
      /*LOAD_EXPLICIT_CHECKPOINT - this is an architecture feature.
        this operation takes an argument that is the index into the
        table of explicit checkpoints.  This operation replaces the
        current execution context & stack with the one in the named
        checkpoint.  See STORE_EXPLICIT_CHECKPOINT above.
      */
      if( firehoseState != Firehose.valid  ){ LOAD_EXPLICIT_CHECKPOINT(0); }
    
      if( currentTime - sval.time > sensor.SameTimeThreshold ){ LOAD_EXPLICIT_CHECKPOINT(1); }
     
      /*LOAD_CURRENT_CHECKPOINT - this is an architecture feature.
        this opeation loads the most recent checkpoint.  The behavior
        is the same as LOAD_EXPLICIT_CHECKPOINT, except this operation
        does not refer into the table of explicit checkpoints, it uses
        the "current" checkpoint instead.
      */ 
      //Implied "bailTo("current-checkpoint")"
      LOAD_CURRENT_CHECKPOINT();
    
    //}
  
}
